import numpy as np
import struct
import matplotlib.pyplot as plt
import random
from sklearn.manifold import TSNE
from sklearn.decomposition import PCA
from sklearn.datasets import load_digits  # 加载手写数字识别数据
from sklearn.cluster import KMeans
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix,classification_report

def my_knn(ts,pre,k,ts_class,class_num):
    #异常判断：k数要少于等于样本数
    if k>ts.shape[0]:
        #k = ts.shape[0]
        raise Exception("n_samples should >= k")

    dis_origin = np.zeros((pre.shape[0],ts.shape[0]))
    print("pre.shape[0]",pre.shape[0])
    print("ts.shape[0]",ts.shape[0])
    for t in range(pre.shape[0]):
        dis = []
        for i in range(ts.shape[0]):
            d = np.linalg.norm(pre[t]-ts[i])
            dis.append(d)
        dis_origin[t] = dis
    print(dis_origin)

    dis_order = np.zeros((pre.shape[0],ts.shape[0]))
    for i in range(dis_order.shape[0]):
        dis_order[i] = dis_origin[i][:]
    for l in range(dis_order.shape[0]):
        dis_order[l].sort()
    print("dis_order",dis_order)

    temp_k = k
    nearest_id = np.zeros((dis_order.shape[0],k))
    for i in range(dis_order.shape[0]):
        example_num = []
        k= temp_k
        for dis_i in dis_order[i]:
            if k>0:
                #print("dis_origin[i]",dis_origin[i])
                #print("dis_i",dis_i)
                num = list(dis_origin[i]).index(dis_i)
                #print("num",num)
                example_num.append(num)
                #print("example_num",example_num)
                dis_origin[i][num] = -100
                k = k-1
        nearest_id[i] = example_num
    print("nearest_id",nearest_id)

    freq_class = np.zeros((nearest_id.shape[0],class_num))
    for exid in range(nearest_id.shape[0]):
        fre_class = np.zeros(class_num)
        #print("exid",exid)
        for i in nearest_id[exid]:
            #print("i",i)
            #print("ts_class[i]",ts_class[i])
            fre_class[ts_class[int(i)]] = fre_class[ts_class[int(i)]]+1
        #print("fre_class",fre_class)
        freq_class[exid] = fre_class
    print("freq_class",freq_class)
    
    final_pre_class = np.zeros((freq_class.shape[0],1))
    for exid in range(freq_class.shape[0]):
        l = list(freq_class[exid])
        final_pre_class[exid] = l.index(max(l))
    print("final_pre_class",final_pre_class)
    
    return final_pre_class
    
if __name__ == '__main__':
    ts1 = np.array([[1,3,9,4,6],
                   [2,5,5,3,8],
                   [9,2,3,7,1]])
    ts2 = np.array([[0,0],
                   [1,0],
                   [0,1],
                   [1,1],
                   [3,3],
                   [4,3],
                   [3,4],
                   [4,4]])
    ts3 = np.array([[1,1],
                   [1,2],
                   [1,3],
                   [2,2],
                   [3,1],
                   [3,2],
                   [3,3]])
    ts4 = np.array([[1,0],
                   [1,1],
                   [1,2],
                   [2,0],
                   [2,1],
                   [2,2],
                   [3,3],
                   [4,3],
                   [2,5],
                   [3,4],
                   [4,4],
                   [5,4],
                   [1,3],
                   [2,3],
                   [0,2],
                   [3,1],
                   [4,1],
                   [5,5]])
    ts_class = np.array([1,2,2,5,3,3,4])

    digits = load_digits()
    ts = digits.data
    print("train_images1.shape",ts.shape)
    train_labels = digits.target
    print("train_labels.shape",train_labels.shape)
    print("Computing t-SNE embedding")
    tsne = TSNE(n_components=2, init='pca',random_state=0) #init='pca'
    train_image1_tsne = tsne.fit_transform(ts)
    print(train_image1_tsne)

    t_min, t_max = train_image1_tsne.min(0), train_image1_tsne.max(0)
    #print("t_min, t_max ",t_min, t_max)
    t_norm = (train_image1_tsne - t_min) / (t_max - t_min)  # 归一化
    print("t_norm",t_norm)
    
    k = 5
    class_num=10
    
    t_train = t_norm[0:1000]
    t_test = t_norm[1000:]
    t_train_labels = train_labels[0:1000]
    t_test_lables = train_labels[1000:]
    
    #a,b = eval(input("请输入要预测类别的样本的两个属性值,逗号分隔"))
    #pre = []
    #pre.append(a)
    #pre.append(b)
    #print("pre",pre)
    #t_test = pre
    final_pred_class = my_knn(t_train,t_test,k,t_train_labels,class_num)
    t_pred_labels = final_pred_class.flatten()
    print("t_test_lables",t_test_lables)
    target_names = ['0', '1', '2','3','4','5','6','7','8','9']
    print(classification_report(t_test_lables, t_pred_labels, target_names=target_names))
    #print("right centroid",KMeans(n_clusters=k).fit_predict(ts))
    colors = ['FIREBRICK','lightcoral','coral','gold','springgreen',
              'darkgreen','skyblue','steelblue','darkgrey','darkorchid']
    plt.figure(figsize=(8, 8))
    for i in range(t_norm.shape[0]):
        plt.text(t_norm[i, 0], t_norm[i, 1], str(train_labels[i]), color=colors[int(train_labels[i])], 
                 fontdict={'weight': 'bold', 'size': 9})#plt.cm.Set1(int(label_pred[i])
    #plt.scatter(final_centroids[:,0],final_centroids[:,1],c='k',marker='*')
    plt.xticks([])
    plt.yticks([])
    plt.show()





















